package tech.yixiyun.framework.kuafu.kits;

import cn.hutool.core.util.ClassUtil;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class ClassKit extends ClassUtil{



    private static String[] classPathes = null;


    public static String[] getJavaClassPaths() {
        if (classPathes != null) {
            return classPathes;
        }
        String[] pathes = ClassUtil.getJavaClassPaths();
        classPathes = new String[pathes.length];
        for (int i = 0; i < pathes.length; i++) {
            String path = pathes[i];
            classPathes[i] = new File(path).toURI().getPath();
        }
        return classPathes;
    }

    /**
     * 检测类是否是能被实例化的Bean类，要求是非抽象非接口非枚举类非注解类
     * @param clazz
     * @return
     */
    public static boolean isBeanableClass(Class clazz) {
        int modifiers = clazz.getModifiers();
        return Modifier.isAbstract(modifiers) == false && Modifier.isInterface(modifiers) ==false && clazz.isAnnotation() == false
                && clazz.isEnum() == false;
    }




    /**
     * 获取应用使用的所有jar路径，不包括jre环境下的jar包
     * @return
     */
    public static String[] getAppJarPaths() {
        String javaHome = System.getProperty("java.home");
        String[] classPaths = getJavaClassPaths();
        List<String> jarPaths = new ArrayList<>();
        for (String classPath : classPaths) {
            if (classPath.startsWith(javaHome)) continue;
            if (classPath.endsWith(".jar")) {
                jarPaths.add(classPath);
            }
        }
        return jarPaths.toArray(new String[0]);
    }

    private static  String[] LOCAL_CLASSPATHS = null;

    /**
     * 获取应用本地类路径，一般都是 classes 路径
     * 如果是模块化开发，可能有多个 classes，
     * 所以这里返回的是数组
     * @return
     */
    public static String[] getAppLocalClassPaths() {
        if (LOCAL_CLASSPATHS == null) {
            String[] classPaths = getJavaClassPaths();
            List<String> localPaths = new ArrayList<>();
            for (String classPath : classPaths) {
                if (classPath.endsWith(".jar")) continue;
                localPaths.add(classPath);

            }
            LOCAL_CLASSPATHS = localPaths.toArray(new String[0]);
        }
        return LOCAL_CLASSPATHS;
    }

    /**
     * 扫描jar包里的类，不包括内部类
     * @param jarPath
     * @return
     */
    public static List<String> scanJarClasses(String jarPath) {
        try {
            JarFile jar = new JarFile(new File(jarPath));
            return scanJarClasses(jar);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 扫描jar包中的所有类，返回的是类的完整路径，例如net.yixiyun.kuafu.utils.ClassUtils
     * @param jar
     * @return
     */
    public static List<String> scanJarClasses(JarFile jar) {
        String separator = System.getProperty("file.separator");
        Enumeration<JarEntry> entries = jar.entries();
        List<String> classes = new ArrayList<>();
        while (entries.hasMoreElements()) {
            JarEntry entry = entries.nextElement();
            String name = entry.getName();
            if (name.charAt(0) == '/') {
                // 获取后面的字符串
                name = name.substring(1);
            }
            if (name.endsWith(".class") && name.contains("$") == false) {
                String replace = name.replaceAll("[\\\\/]", ".");
                replace = replace.substring(0, replace.length() - 6); //去掉尾部.class
                classes.add(replace);
            }
        }
        return classes;
    }

    /**
     * 扫描本地路径下的所有类，返回类的全路径集合
     * @param path 绝对路径
     * @param recurse 是否递归扫描子文件夹
     * @return
     */
    public static List<String> scanLocalClasses(String path, boolean recurse) {
        File dir = new File(path);
        if (dir.exists() == false || dir.isDirectory() == false) {
            return Collections.emptyList();
        }
        List<String> list = new ArrayList<>();
        /*
            过滤出非内部类的class文件，如果需要递归子文件夹的话，就要包括文件夹
            这里判断是否是内部类就是依据文件名中是否包含$
            所以要求项目中类的命名不能包含$
         */
        File[] files = dir.listFiles(file -> (recurse && file.isDirectory()) || (file.getName().endsWith(".class") && file.getName().contains("$") == false));
        String classPath = null;
        for (String localClasspath : getAppLocalClassPaths()) {
            if (path.startsWith(localClasspath)) {
                classPath = localClasspath;
                break;
            }
        }

        for (File file : files) {
            if (file.isDirectory()) {
                list.addAll(scanLocalClasses(file.toURI().getPath(), recurse));
            } else {
                String filePath = file.toURI().getPath();
                filePath = filePath.replace(classPath, "").replaceAll( "[/|\\\\]" , ".");
                if (filePath.startsWith(".")) {//filepath可能以/开头
                    filePath = filePath.substring(1);
                }
                filePath = filePath.substring(0, filePath.length()-6);//去掉尾部.class，不能用替换
                list.add(filePath);
            }
        }

        return list;
    }

    /**
     * 获取一个类的字段，包括自己的所有字段和继承来的protect字段
     * @param clazz
     * @return
     */
    public static List<Field> getFields(Class clazz) {
        List<Field> list = new ArrayList<>();
        Field[] fields = clazz.getDeclaredFields();
        if (fields.length > 0) {
            for (Field field : fields) {
                list.add(field);
            }
        }
        Class parentClass = clazz;
        while ((parentClass = parentClass.getSuperclass()) != Object.class && parentClass != null) {
            fields = parentClass.getDeclaredFields();
            for (Field field : fields) {
                if (Modifier.isProtected(field.getModifiers())) {
                    list.add(field);
                }
            }
        }

        return list;
    }



}
